package com.gzx.plugin.tjzy.modular.founds.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gzx.plugin.tjzy.modular.founds.bo.GzxFoundsAmountBo;
import com.gzx.plugin.tjzy.modular.founds.bo.GzxFoundsFlowAddBo;
import com.gzx.plugin.tjzy.modular.founds.bo.GzxFoundsFlowQueryBo;
import com.gzx.plugin.tjzy.modular.founds.bo.GzxTransMethodBo;
import com.gzx.plugin.tjzy.modular.founds.constant.FoundsConstant;
import com.gzx.plugin.tjzy.modular.founds.entity.GzxFoundsFlowRecord;
import com.gzx.plugin.tjzy.modular.founds.lock.RedisTransLock;
import com.gzx.plugin.tjzy.modular.founds.mapper.GzxFoundsFlowMapper;
import com.gzx.plugin.tjzy.modular.founds.service.GzxFoundsFlowService;
import com.gzx.plugin.tjzy.modular.founds.vo.GzxFoundsAvailableVo;
import com.gzx.plugin.tjzy.modular.founds.vo.GzxFoundsFlowVo;
import com.gzx.plugin.tjzy.modular.project.entity.GzxProject;
import com.gzx.plugin.tjzy.modular.project.entity.vo.GzxProjectVo;
import com.gzx.plugin.tjzy.modular.project.mapper.GzxProjectMapper;
import com.gzx.plugin.tjzy.modular.supplier.entity.GzxSupplier;
import com.gzx.plugin.tjzy.modular.supplier.service.GzxSupplierService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.common.tenant.TenantContext;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;

/**
 * 充值电话短信流水记录 gzx_founds_flow_record
 *
 * @author xbl
 * &#064;date  2025-03-19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GzxFoundsFlowServiceImpl implements GzxFoundsFlowService {

    private final GzxFoundsFlowMapper baseMapper;

    /**
     * 项目
     */
    private final GzxProjectMapper projectMapper;

    /**
     * 供应商
     */
    private final GzxSupplierService supplierService;

    /**
     * 分布式锁
     */
    private final RedisTransLock redisTransLock;

    //查看某个产品的短信花了多少钱
    @DS("tjzy")
    @Override
    public List<GzxFoundsFlowVo> productAmount(GzxFoundsAmountBo foundsAmountBo) {
        return baseMapper.productAmount(foundsAmountBo);
    }

    @DS("tjzy")
    @Override
    public GzxFoundsAvailableVo getAvaliableByCode(String projectCode) {
        return baseMapper.getAvaliableByCode(projectCode);
    }

    /**
     * 分页查询充值电话短信流水记录
     */
    @DS("tjzy")
    @DSTransactional(rollbackFor = Exception.class)
    @Override
    public Page<GzxFoundsFlowVo> page(GzxFoundsFlowQueryBo foundsFlowQueryBo) {
        Page<GzxFoundsFlowVo> flowVoPage = baseMapper.selectVoPage(new Page<>(foundsFlowQueryBo.getCurrent(), foundsFlowQueryBo.getSize()),
                Wrappers.<GzxFoundsFlowRecord>lambdaQuery()
                        //只查询部分列
                        .select(GzxFoundsFlowRecord::getId, GzxFoundsFlowRecord::getProjectName, GzxFoundsFlowRecord::getFoundsPre, GzxFoundsFlowRecord::getFoundsAvailable, GzxFoundsFlowRecord::getFoundsAmount, GzxFoundsFlowRecord::getFoundsType, GzxFoundsFlowRecord::getTransType, GzxFoundsFlowRecord::getCreateTime, GzxFoundsFlowRecord::getCreateUser)
                        .eq(StringUtils.isNotBlank(foundsFlowQueryBo.getProjectName()), GzxFoundsFlowRecord::getProjectName, foundsFlowQueryBo.getProjectName())
                        .eq(GzxFoundsFlowRecord::getFoundsType, foundsFlowQueryBo.getFoundsType())
                        //查询全部是-1
                        .eq(foundsFlowQueryBo.getTransType() != -1, GzxFoundsFlowRecord::getTransType, foundsFlowQueryBo.getTransType())
                        .ge(StringUtils.isNotBlank(foundsFlowQueryBo.getProjectBeginTime()), GzxFoundsFlowRecord::getCreateTime, foundsFlowQueryBo.getProjectBeginTime())
                        .le(StringUtils.isNotBlank(foundsFlowQueryBo.getProjectEndTime()), GzxFoundsFlowRecord::getCreateTime, foundsFlowQueryBo.getProjectEndTime())
                        .orderByDesc(GzxFoundsFlowRecord::getCreateTime));

        //创建人为空的，默认拼接SYSTEM
        flowVoPage.getRecords().forEach(flowVo -> {
            if (StringUtils.isBlank(flowVo.getCreateUserName())) {
                flowVo.setCreateUserName("SYSTEM");
            }
        });
        return flowVoPage;
    }

    /**
     * 保存充值电话短信流水记录图片
     */
    @DS("tjzy")
    @DSTransactional(rollbackFor = Exception.class)
    @Override
    public GzxProjectVo transRecharge(MultipartFile file, GzxFoundsFlowAddBo bo) throws IOException {
        if (!redisTransLock.getLock()) {
            log.warn("充值电话短信流水记录图片锁失败");
            return new GzxProjectVo();
        }
        //根据项目编码获取项目信息
        GzxProject gzxProject = projectMapper.selectOne(new LambdaQueryWrapper<GzxProject>().eq(GzxProject::getProjectCode, bo.getProjectCode()));

        //计算充值后的金额
        BigDecimal foundsAvailable = gzxProject.getSmsAmount().add(bo.getFoundsAmount());

        // 当前登录用户
        SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();

        GzxFoundsFlowRecord flowRecord = new GzxFoundsFlowRecord();
        //这个接口进来的都是在界面充值的
        flowRecord.setTransType(FoundsConstant.TRANS_TYPE_RECHARGE);
        //项目信息
        flowRecord.setProjectCode(bo.getProjectCode());
        flowRecord.setProjectName(gzxProject.getProjectName());
        //电话还是短信
        flowRecord.setFoundsType(bo.getFoundsType());
        //图片
        flowRecord.setApplyPhoto(file.getBytes());
        flowRecord.setFoundsRemark(bo.getFoundsRemark());
        //变动前，变动金额，变动后
        flowRecord.setFoundsPre(gzxProject.getSmsAmount());
        flowRecord.setFoundsAmount(bo.getFoundsAmount());
        flowRecord.setFoundsAvailable(foundsAvailable);
        //租户，创建人等
        flowRecord.setTenantId(loginUser.getTenantId());
        //获取项目信息
        baseMapper.insert(flowRecord);

        //修改项目金额
        if (FoundsConstant.FOUNDS_TYPE_SMS == bo.getFoundsType()) {
            GzxProject project = new GzxProject();
            project.setId(gzxProject.getId());
            project.setSmsAmount(gzxProject.getSmsAmount().add(bo.getFoundsAmount()));
            //充值短信
            projectMapper.updateById(project);
        } else if (FoundsConstant.FOUNDS_TYPE_PHONE == bo.getFoundsType()) {
            GzxProject project = new GzxProject();
            project.setId(gzxProject.getId());
            project.setPhoneAmount(gzxProject.getPhoneAmount().add(bo.getFoundsAmount()));
            //充值电话
            projectMapper.updateById(project);
        }
        //充值完成之后要返回余额，冻结金额
        GzxProjectVo projectVo = new GzxProjectVo();
        //可用余额=余额-冻结
        projectVo.setSmsAmount(foundsAvailable);
        projectVo.setSmsFreezeAmount(gzxProject.getSmsFreezeAmount());
        return projectVo;
    }

    /**
     * 详情充值电话短信流水记录
     */
    @DS("tjzy")
    @Override
    public GzxFoundsFlowVo detailFoundsFlow(String id) {
        return baseMapper.selectVoById(id, GzxFoundsFlowVo.class);
    }

    /**
     * 消费
     */
    @DS("tjzy")
    @DSTransactional(rollbackFor = Exception.class)
    @Override
    public boolean transConsume(GzxTransMethodBo bo) {
        log.info("消费开始：{} ", bo);
        if (!redisTransLock.getLock()) {
            log.error("消费失败：消费获取锁失败");
            return false;
        }
        bo.setTransType(FoundsConstant.TRANS_TYPE_CONSUME);
        try {
            TenantContext.disableTenantFilter();
            //后期扩展电话类型的消费，目前只支持短信消费 FIX
            if (0 == bo.getRowNum() || StringUtils.isEmpty(bo.getSupplierCode()) || StringUtils.isEmpty(bo.getProjectCode()) || StringUtils.isEmpty(bo.getTenantId())) {
                log.error("消费失败：参数为空 {} ", bo);
                return false;
            }
            //根据项目代码获取项目金额
            GzxProject gzxProject = projectMapper.selectOne(new LambdaQueryWrapper<GzxProject>().eq(GzxProject::getProjectCode, bo.getProjectCode()));
            if (null == gzxProject) {
                log.error("消费失败：项目不存在 {} ", bo.getFoundsType());
                return false;
            }

            BigDecimal smsAmount = gzxProject.getSmsAmount();
            if (smsAmount.compareTo(BigDecimal.ZERO) <= 0) {
                log.error("消费失败：短信余额不足 {} ", bo.getFoundsType());
                return false;
            }

            //根据供应商代码获取供应商单价
            GzxSupplier gzxSupplier = supplierService.getSupplierByCode(bo.getSupplierCode());
            if (null == gzxSupplier) {
                log.error("消费失败：供应商不存在 {} ", bo.getFoundsType());
                return false;
            }

            BigDecimal billingMethod = new BigDecimal(gzxSupplier.getBillingMethod());
            if (billingMethod.compareTo(BigDecimal.ZERO) <= 0) {
                log.error("消费失败：供应商单价为空 {} ", bo.getFoundsType());
                return false;
            }

            //根据供应商单价和条数计算总金额
            BigDecimal totalAmount = billingMethod.multiply(new BigDecimal(bo.getRowNum()));

            //剩余额度是否够扣减
            BigDecimal remainAmount = gzxProject.getSmsAmount().subtract(totalAmount);
            if (remainAmount.compareTo(BigDecimal.ZERO) < 0) {
                log.error("消费失败：短信额度不足 {} ", bo.getFoundsType());
                return false;
            }
            //记录一条消费流水记录
            GzxFoundsFlowRecord flowRecord = new GzxFoundsFlowRecord();
            //项目信息
            flowRecord.setProjectCode(bo.getProjectCode());
            flowRecord.setProjectName(gzxProject.getProjectName());
            //消费类型和交易方式
            flowRecord.setFoundsType(bo.getFoundsType());
            flowRecord.setTransType(bo.getTransType());
            //变动前金额，金额，变动后金额
            flowRecord.setFoundsPre(gzxProject.getSmsAmount());
            flowRecord.setFoundsAmount(totalAmount);
            flowRecord.setFoundsAvailable(remainAmount);
            //创建人，创建时间，租户id
            flowRecord.setTenantId(bo.getTenantId());
            baseMapper.insert(flowRecord);

            //更新项目金额
            GzxProject project = new GzxProject();
            project.setId(gzxProject.getId());
            project.setSmsAmount(remainAmount);
            projectMapper.updateById(project);
            return true;
        } catch (Exception e) {
            log.error("消费失败： ", e);
            return false;
        } finally {
            TenantContext.enableTenantFilter();
            TenantContext.clear();
        }
    }

    /**
     * 冻结
     */
    @DS("tjzy")
    @DSTransactional(rollbackFor = Exception.class)
    @Override
    public boolean transFreeze(GzxTransMethodBo bo) {
        log.info("冻结开始：{} ", bo);
        if (!redisTransLock.getLock()) {
            log.error("冻结开始：冻结获取锁失败");
            return false;
        }
        try {
            TenantContext.disableTenantFilter();
            //后期扩展电话类型的消费，目前只支持短信消费 FIX
            if (0 == bo.getRowNum() || StringUtils.isEmpty(bo.getSupplierCode()) || StringUtils.isEmpty(bo.getProjectCode()) || StringUtils.isEmpty(bo.getTenantId())) {
                log.error("冻结失败：参数为空 {} ", bo);
                return false;
            }
            //根据项目代码获取项目金额
            GzxProject gzxProject = projectMapper.selectOne(new LambdaQueryWrapper<GzxProject>().eq(GzxProject::getProjectCode, bo.getProjectCode()));
            if (null == gzxProject) {
                log.error("冻结失败：项目不存在 {} ", bo.getFoundsType());
                return false;
            }

            BigDecimal smsAmount = gzxProject.getSmsAmount();
            if (smsAmount.compareTo(BigDecimal.ZERO) <= 0) {
                log.error("冻结失败：短信余额不足 {} ", bo.getFoundsType());
                return false;
            }

            //根据供应商代码获取供应商单价
            GzxSupplier gzxSupplier = supplierService.getSupplierByCode(bo.getSupplierCode());
            if (null == gzxSupplier) {
                log.error("冻结失败：供应商不存在 {} ", bo.getFoundsType());
                return false;
            }

            BigDecimal billingMethod = new BigDecimal(gzxSupplier.getBillingMethod());
            if (billingMethod.compareTo(BigDecimal.ZERO) <= 0) {
                log.error("冻结失败：供应商单价为空 {} ", bo.getFoundsType());
                return false;
            }

            //根据供应商单价和条数计算总金额
            BigDecimal totalAmount = billingMethod.multiply(new BigDecimal(bo.getRowNum()));

            //冻结的是否比余额多
            BigDecimal remainAmount = gzxProject.getSmsFreezeAmount().add(totalAmount);
            if (remainAmount.compareTo(gzxProject.getSmsAmount()) > 0) {
                log.error("冻结失败：冻结的比余额多 {} ", bo.getFoundsType());
                //冻结的比余额多的时候，冻结金额=余额
                remainAmount = gzxProject.getSmsAmount();
            }
            //记录一条消费流水记录
            GzxFoundsFlowRecord flowRecord = new GzxFoundsFlowRecord();
            //项目信息
            flowRecord.setProjectCode(bo.getProjectCode());
            flowRecord.setProjectName(gzxProject.getProjectName());
            //消费类型和交易方式
            flowRecord.setFoundsType(bo.getFoundsType());
            flowRecord.setTransType(FoundsConstant.TRANS_TYPE_FREEZE);
            //变动前金额，金额，变动后金额
            flowRecord.setFoundsPre(gzxProject.getSmsFreezeAmount());
            flowRecord.setFoundsAmount(totalAmount);
            //只修改冻结金额，所以可用余额没变
            flowRecord.setFoundsAvailable(remainAmount);
            //创建人，创建时间，租户id
            flowRecord.setTenantId(bo.getTenantId());
            baseMapper.insert(flowRecord);

            //更新项目金额：冻结时只修改冻结金额
            GzxProject project = new GzxProject();
            project.setId(gzxProject.getId());
            project.setSmsFreezeAmount(remainAmount);
            projectMapper.updateById(project);
            return true;
        } catch (Exception e) {
            log.error("冻结失败 err ", e);
            return false;
        } finally {
            TenantContext.enableTenantFilter();
            TenantContext.clear();
        }
    }

    /**
     * 解冻
     */
    @DS("tjzy")
    @DSTransactional(rollbackFor = Exception.class)
    @Override
    public boolean transUnfreeze(GzxTransMethodBo bo) {
        log.info("解冻开始：{} ", bo);
        if (!redisTransLock.getLock()) {
            log.error("解冻开始: 解冻获取锁失败");
            return false;
        }
        try {
            TenantContext.disableTenantFilter();
            //后期扩展电话类型的消费，目前只支持短信消费 FIX
            if (0 == bo.getRowNum() || StringUtils.isEmpty(bo.getSupplierCode()) || StringUtils.isEmpty(bo.getProjectCode()) || StringUtils.isEmpty(bo.getTenantId())) {
                log.error("解冻失败：参数为空 {} ", bo);
                return false;
            }
            //根据项目代码获取项目金额
            GzxProject gzxProject = projectMapper.selectOne(new LambdaQueryWrapper<GzxProject>().eq(GzxProject::getProjectCode, bo.getProjectCode()));
            if (null == gzxProject) {
                log.error("解冻失败：项目不存在 {} ", bo.getFoundsType());
                return false;
            }

            //根据供应商代码获取供应商单价
            GzxSupplier gzxSupplier = supplierService.getSupplierByCode(bo.getSupplierCode());
            if (null == gzxSupplier) {
                log.error("解冻失败：供应商不存在 {} ", bo.getFoundsType());
                return false;
            }

            BigDecimal billingMethod = new BigDecimal(gzxSupplier.getBillingMethod());
            if (billingMethod.compareTo(BigDecimal.ZERO) <= 0) {
                log.error("解冻失败：供应商单价为空 {} ", bo.getFoundsType());
                return false;
            }

            //根据供应商单价和条数计算总金额
            BigDecimal totalAmount = billingMethod.multiply(new BigDecimal(bo.getRowNum()));

            //冻结金额-解冻的金额
            BigDecimal remainAmount = gzxProject.getSmsFreezeAmount().subtract(totalAmount);
            if (remainAmount.compareTo(BigDecimal.ZERO) < 0) {
                log.error("解冻失败：短信额度不足 {} ", bo.getFoundsType());
                //解冻完 < 0 的情况
                remainAmount = BigDecimal.ZERO;
            }

            //记录一条消费流水记录
            GzxFoundsFlowRecord flowRecord = new GzxFoundsFlowRecord();
            //项目信息
            flowRecord.setProjectCode(bo.getProjectCode());
            flowRecord.setProjectName(gzxProject.getProjectName());
            //消费类型和交易方式
            flowRecord.setFoundsType(bo.getFoundsType());
            flowRecord.setTransType(FoundsConstant.TRANS_TYPE_UNFREEZE);
            //变动前金额，金额，变动后金额
            flowRecord.setFoundsPre(gzxProject.getSmsFreezeAmount());
            flowRecord.setFoundsAmount(totalAmount);
            flowRecord.setFoundsAvailable(remainAmount);
            //创建人，创建时间，租户id
            flowRecord.setTenantId(bo.getTenantId());
            baseMapper.insert(flowRecord);

            //更新项目金额
            GzxProject project = new GzxProject();
            project.setId(gzxProject.getId());
            //只修改解冻的金额
            project.setSmsFreezeAmount(remainAmount);
            projectMapper.updateById(project);
            return true;
        } catch (Exception e) {
            log.error("冻结失败 err ", e);
            return false;
        } finally {
            TenantContext.enableTenantFilter();
            TenantContext.clear();
        }
    }

}
